bun tanstack start

安装量: 71
排名: #10837

安装

npx skills add https://github.com/secondsky/claude-skills --skill 'Bun TanStack Start'

Bun TanStack Start Run TanStack Start (full-stack React framework) with Bun. Quick Start

Create new TanStack Start project

bunx create-tanstack-start@latest my-app cd my-app

Install dependencies

bun install

Development

bun run dev

Build

bun run build

Preview

bun run start Project Setup package.json { "scripts" : { "dev" : "vinxi dev" , "build" : "vinxi build" , "start" : "vinxi start" } , "dependencies" : { "@tanstack/react-router" : "^1.139.0" , "@tanstack/start" : "^1.120.0" , "react" : "^19.2.0" , "react-dom" : "^19.2.0" , "vinxi" : "^0.5.10" } } app.config.ts import { defineConfig } from "@tanstack/start/config" ; export default defineConfig ( { server : { preset : "bun" , } , } ) ; File-Based Routing app/ ├── routes/ │ ├── __root.tsx # Root layout │ ├── index.tsx # / │ ├── about.tsx # /about │ ├── users/ │ │ ├── index.tsx # /users │ │ └── $userId.tsx # /users/:userId │ └── api/ │ └── users.ts # /api/users └── client.tsx Route Components Basic Route // app/routes/index.tsx import { createFileRoute } from "@tanstack/react-router" ; export const Route = createFileRoute ( "/" ) ( { component : Home , } ) ; function Home ( ) { return < h1

Welcome Home </ h1

; } Route with Loader // app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router" ; export const Route = createFileRoute ( "/users/" ) ( { loader : async ( ) => { const response = await fetch ( "/api/users" ) ; return response . json ( ) ; } , component : Users , } ) ; function Users ( ) { const users = Route . useLoaderData ( ) ; return ( < ul

{ users . map ( ( user ) => ( < li key = { user . id }

{ user . name } </ li

) ) } </ ul

) ; } Dynamic Routes // app/routes/users/$userId.tsx import { createFileRoute } from "@tanstack/react-router" ; export const Route = createFileRoute ( "/users/$userId" ) ( { loader : async ( { params } ) => { const response = await fetch ( /api/users/ ${ params . userId } ) ; return response . json ( ) ; } , component : UserDetail , } ) ; function UserDetail ( ) { const user = Route . useLoaderData ( ) ; const { userId } = Route . useParams ( ) ; return ( < div

< h1

{ user . name } </ h1

< p

User ID: { userId } </ p

</ div

) ; } Server Functions Define Server Function // app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router" ; import { createServerFn } from "@tanstack/start" ; import { Database } from "bun:sqlite" ; const getUsers = createServerFn ( "GET" , async ( ) => { const db = new Database ( "data.sqlite" ) ; const users = db . query ( "SELECT * FROM users" ) . all ( ) ; db . close ( ) ; return users ; } ) ; const createUser = createServerFn ( "POST" , async ( name : string ) => { const db = new Database ( "data.sqlite" ) ; db . run ( "INSERT INTO users (name) VALUES (?)" , [ name ] ) ; db . close ( ) ; return { success : true } ; } ) ; export const Route = createFileRoute ( "/users/" ) ( { loader : ( ) => getUsers ( ) , component : Users , } ) ; function Users ( ) { const users = Route . useLoaderData ( ) ; const handleSubmit = async ( e : React . FormEvent < HTMLFormElement

) => { e . preventDefault ( ) ; const formData = new FormData ( e . currentTarget ) ; const name = formData . get ( "name" ) as string ; await createUser ( name ) ; // Refetch or update state } ; return ( < div

< form onSubmit = { handleSubmit }

< input name = " name " placeholder = " Name " /> < button type = " submit "

Add User </ button

</ form

< ul

{ users . map ( ( user ) => ( < li key = { user . id }

{ user . name } </ li

) ) } </ ul

</ div

) ; } Server Function with Context import { createServerFn } from "@tanstack/start" ; import { getWebRequest } from "@tanstack/start/server" ; const getSession = createServerFn ( "GET" , async ( ) => { const request = getWebRequest ( ) ; const cookies = request . headers . get ( "Cookie" ) ; // Parse and validate session return { userId : "123" , role : "admin" } ; } ) ; const protectedAction = createServerFn ( "POST" , async ( data : any ) => { const session = await getSession ( ) ; if ( session . role !== "admin" ) { throw new Error ( "Unauthorized" ) ; } // Perform action return { success : true } ; } ) ; API Routes // app/routes/api/users.ts import { createAPIFileRoute } from "@tanstack/start/api" ; import { Database } from "bun:sqlite" ; export const Route = createAPIFileRoute ( "/api/users" ) ( { GET : async ( { request } ) => { const db = new Database ( "data.sqlite" ) ; const users = db . query ( "SELECT * FROM users" ) . all ( ) ; db . close ( ) ; return Response . json ( users ) ; } , POST : async ( { request } ) => { const { name } = await request . json ( ) ; const db = new Database ( "data.sqlite" ) ; db . run ( "INSERT INTO users (name) VALUES (?)" , [ name ] ) ; db . close ( ) ; return Response . json ( { success : true } ) ; } , } ) ; Root Layout // app/routes/__root.tsx import { createRootRoute , Link , Outlet } from "@tanstack/react-router" ; export const Route = createRootRoute ( { component : Root , } ) ; function Root ( ) { return ( < html

< head

< meta charSet = " utf-8 " /> < meta name = " viewport " content = " width=device-width, initial-scale=1 " /> < title

My App </ title

</ head

< body

< nav

< Link to = " / "

Home </ Link

< Link to = " /users "

Users </ Link

< Link to = " /about "

About </ Link

</ nav

< main

< Outlet /> </ main

</ body

</ html

) ; } Error Handling // app/routes/users/$userId.tsx export const Route = createFileRoute ( "/users/$userId" ) ( { loader : async ( { params } ) => { const response = await fetch ( /api/users/ ${ params . userId } ) ; if ( ! response . ok ) { throw new Error ( "User not found" ) ; } return response . json ( ) ; } , errorComponent : ( { error } ) => ( < div

< h1

Error </ h1

< p

{ error . message } </ p

</ div

) , pendingComponent : ( ) => < div

Loading... </ div

, component : UserDetail , } ) ; Search Params // app/routes/users/index.tsx import { createFileRoute } from "@tanstack/react-router" ; import { z } from "zod" ; const searchSchema = z . object ( { page : z . number ( ) . default ( 1 ) , limit : z . number ( ) . default ( 10 ) , search : z . string ( ) . optional ( ) , } ) ; export const Route = createFileRoute ( "/users/" ) ( { validateSearch : searchSchema , loader : async ( { search } ) => { const { page , limit , search : query } = search ; // Fetch with pagination return fetchUsers ( { page , limit , query } ) ; } , component : Users , } ) ; Deployment Build for Bun NITRO_PRESET = bun bun run build bun .output/server/index.mjs Docker FROM oven/bun:1 AS builder WORKDIR /app COPY package.json bun.lockb ./ RUN bun install --frozen-lockfile COPY . . RUN bun run build FROM oven/bun:1 WORKDIR /app COPY --from = builder /app/.output ./output EXPOSE 3000 CMD [ "bun" , ".output/server/index.mjs" ] Common Errors Error Cause Fix Cannot find bun:sqlite Wrong preset Set server.preset: "bun" Server function failed Network error Check function definition Route not found File naming Check route file location Hydration mismatch Server/client diff Check loader data When to Load References Load references/router-api.md when: Advanced routing patterns Route guards Nested layouts Load references/forms.md when: Form handling Mutations Optimistic updates

返回排行榜